<?php


namespace XinSheng;

use Fize\Math\Financial;

/**
 * 报价方案
 */
class Solution
{
    /**
     * @var int 期次
     */
    protected $issues;

    /**
     * @var string 起租日
     */
    protected $startDate;

    /**
     * @var int 支付方式：0-期末支付；1-期初支付
     */
    protected $paymentMode;

    /**
     * @var int 每期月数
     */
    protected $issueMonths;

    /**
     * @var int 保留小数位
     */
    protected $scale;

    /**
     * @var float 转让价款
     */
    protected $leaseAmount;

    /**
     * @var float 首付款
     */
    protected $downPayment;

    /**
     * @var float 预付款
     */
    protected $deposit;

    /**
     * @var float 留购价
     */
    protected $residualValue;

    /**
     * @var float 手续费
     */
    protected $serviceAmount;

    /**
     * @var float 内部年化IRR
     */
    protected $interestRate;

    /**
     * @var array 其他费用
     */
    protected $otherfees;

    /**
     * @var float|null 首次利息本金比
     */
    protected $interestRateFirst;

    /**
     * @var float 概算本金
     */
    protected $principal;

    /**
     * @var array 计划表1
     */
    protected $plans1;

    /**
     * @var float 表1年利率
     */
    protected $outsideRate1;

    /**
     * @var float 表1实际内部年化IRR
     */
    protected $insideRate1;

    /**
     * @var float 转让价款比例
     */
    protected $leaseAmountRatio;

    /**
     * @var float 首付款比例
     */
    protected $downPaymentRatio;

    /**
     * @var float 预付款比例
     */
    protected $depositRatio;

    /**
     * @var float 留购价比例
     */
    protected $residualValueRatio;

    /**
     * @var float 手续费比例
     */
    protected $serviceAmountRatio;

    /**
     * @var float 内部年化IRR2
     */
    protected $interestRate2;

    /**
     * @var array 其他费用2
     */
    protected $otherfees2;

    /**
     * @var float 转让价款2
     */
    protected $leaseAmount2;

    /**
     * @var float 首付款2
     */
    protected $downPayment2;

    /**
     * @var float 概算本金2
     */
    protected $principal2;

    /**
     * @var float 预付款2
     */
    protected $deposit2;

    /**
     * @var float 留购价2
     */
    protected $residualValue2;

    /**
     * @var float 手续费2
     */
    protected $serviceAmount2;

    /**
     * @var array 计划表2
     */
    protected $plans2;

    /**
     * @var float 表2年利率
     */
    protected $outsideRate2;

    /**
     * @var float 表2实际内部年化IRR
     */
    protected $insideRate2;

    /**
     * @var float 表2实际融资额
     */
    protected $platformBase2;

    /**
     * @var array 其他费用3
     */
    protected $otherfees3;

    /**
     * @var float 转让价款3
     */
    protected $leaseAmount3;

    /**
     * @var float 首付款3
     */
    protected $downPayment3;

    /**
     * @var float 概算本金3
     */
    protected $principal3;

    /**
     * @var float 预付款3
     */
    protected $deposit3;

    /**
     * @var float 留购价3
     */
    protected $residualValue3;

    /**
     * @var float 手续费3
     */
    protected $serviceAmount3;

    /**
     * @var array 计划表3
     */
    protected $plans3;

    /**
     * @var float 表3年利率
     */
    protected $outsideRate3;

    /**
     * @var float 表3实际内部年化IRR
     */
    protected $insideRate3;

    /**
     * @var float 转让价款比例4
     */
    protected $leaseAmountRatio4;

    /**
     * @var float 首付款比例4
     */
    protected $downPaymentRatio4;

    /**
     * @var float 预付款比例4
     */
    protected $depositRatio4;

    /**
     * @var float 留购价比例4
     */
    protected $residualValueRatio4;

    /**
     * @var float 手续费比例4
     */
    protected $serviceAmountRatio4;

    /**
     * @var float 内部年化IRR4
     */
    protected $interestRate4;

    /**
     * @var array 其他费用4
     */
    protected $otherfees4;

    /**
     * @var float 转让价款4
     */
    protected $leaseAmount4;

    /**
     * @var float 首付款4
     */
    protected $downPayment4;

    /**
     * @var float 概算本金4
     */
    protected $principal4;

    /**
     * @var float 预付款4
     */
    protected $deposit4;

    /**
     * @var float 留购价4
     */
    protected $residualValue4;

    /**
     * @var float 手续费4
     */
    protected $serviceAmount4;

    /**
     * @var array 计划表4
     */
    protected $plans4;

    /**
     * @var float 表4年利率
     */
    protected $outsideRate4;

    /**
     * @var float 表4实际内部年化IRR
     */
    protected $insideRate4;

    /**
     * @var array 其他费用5
     */
    protected $otherfees5;

    /**
     * @var float 概算本金5
     */
    protected $principal5;

    /**
     * @var float 转让价款5
     */
    protected $leaseAmount5;

    /**
     * @var float 首付款5
     */
    protected $downPayment5;

    /**
     * @var float 预付款5
     */
    protected $deposit5;


    /**
     * @var float 留购价5
     */
    protected $residualValue5;

    /**
     * @var float 手续费5
     */
    protected $serviceAmount5;

    /**
     * @var array 计划表5
     */
    protected $plans5;

    /**
     * @var float 表5年利率
     */
    protected $outsideRate5;

    /**
     * 初始化
     * @param int         $issues      期次
     * @param string|null $startDate   起租日，指定起租日则还款计划带有还款日期
     * @param int         $paymentMode 支付方式：0-期末支付；1-期初支付
     * @param int         $issueMonths 每期月数
     * @param int         $scale       保留小数位
     */
    public function __construct($issues, $startDate = null, $paymentMode = 0, $issueMonths = 1, $scale = 2)
    {
        $this->issues = $issues;
        $this->startDate = $startDate;
        $this->paymentMode = $paymentMode;
        $this->issueMonths = $issueMonths;
        $this->scale = $scale;
    }

    /**
     * 设置表1参数
     * @param float      $leaseAmount       转让价款
     * @param float      $downPayment       首付款
     * @param float      $deposit           预付款
     * @param float      $residualValue     留购价
     * @param float      $serviceAmount     手续费
     * @param float      $interestRate      内部年化IRR
     * @param array      $otherfees         其他费用
     * @param float|null $interestRateFirst 首次利息本金比，null表示不指定
     */
    public function set1($leaseAmount, $downPayment, $deposit, $residualValue, $serviceAmount, $interestRate, $otherfees = [], $interestRateFirst = null)
    {
        $this->leaseAmount = $leaseAmount;
        $this->downPayment = $downPayment;
        $this->deposit = $deposit;
        $this->residualValue = $residualValue;
        $this->serviceAmount = $serviceAmount;
        $this->interestRate = $interestRate;
        $this->otherfees = $otherfees;
        $this->interestRateFirst = $interestRateFirst;

        $this->principal = round($this->leaseAmount - $this->downPayment, $this->scale);
        $this->plans1 = null;  // 重新生成计划表1
    }

    /**
     * 获取表1租金计划
     * @return array
     */
    public function getPlans1()
    {
        if (is_null($this->plans1)) {
            $mbi = new ModelByIrr(
                $this->leaseAmount, $this->downPayment, $this->deposit, $this->residualValue, $this->serviceAmount,
                $this->interestRate, $this->issues, $this->otherfees, $this->interestRateFirst, $this->paymentMode,
                $this->issueMonths, $this->scale
            );
            $this->plans1 = $mbi->getPlan($this->startDate);
            $this->outsideRate1 = $mbi->getOutsideRate();
        }
        return $this->plans1;
    }

    /**
     * 获取表1外部年化利率
     * @return float
     */
    public function getOutsideRate1()
    {
        if (is_null($this->outsideRate1)) {
            $this->getPlans1();
        }
        return $this->outsideRate1;
    }

    /**
     * 获取表1实际内部年化IRR
     * @return float
     */
    public function getInsideRate1()
    {
        if (is_null($this->insideRate1)) {
            $this->getPlans1();
            $cashflow = [];
            foreach ($this->plans1 as $plan) {
                $cashflow[] = $plan['cash_flow'];
            }
            $this->insideRate1 = Financial::irr($cashflow) * 12 / $this->issueMonths;
        }
        return $this->insideRate1;
    }

    /**
     * 设置表2参数
     * @param float $leaseAmountRatio   转让价款比例
     * @param float $downPaymentRatio   首付款比例
     * @param float $depositRatio       预付款比例
     * @param float $residualValueRatio 留购价比例
     * @param float $serviceAmountRatio 手续费比例
     * @param float $interestRate2      内部年化IRR2
     * @param array $otherfees2         其他费用2
     */
    public function set2($leaseAmountRatio, $downPaymentRatio, $depositRatio, $residualValueRatio, $serviceAmountRatio, $interestRate2, $otherfees2 = [])
    {
        $this->leaseAmountRatio = $leaseAmountRatio;
        $this->downPaymentRatio = $downPaymentRatio;
        $this->depositRatio = $depositRatio;
        $this->residualValueRatio = $residualValueRatio;
        $this->serviceAmountRatio = $serviceAmountRatio;
        $this->interestRate2 = $interestRate2;
        $this->otherfees2 = $otherfees2;

        $this->leaseAmount2 = round($this->leaseAmount * $this->leaseAmountRatio, $this->scale);
        $this->downPayment2 = round($this->downPayment * $this->downPaymentRatio, $this->scale);
        $this->deposit2 = round($this->deposit * $this->depositRatio, $this->scale);
        $this->residualValue2 = round($this->residualValue * $this->residualValueRatio, $this->scale);
        $this->serviceAmount2 = round($this->serviceAmount * $this->serviceAmountRatio, $this->scale);

        $this->principal2 = round($this->leaseAmount2 - $this->downPayment2, $this->scale);
        $this->platformBase2 = round($this->leaseAmount2 - $this->downPayment2 - $this->deposit2, $this->scale);
        $this->plans2 = null;  // 重新生成计划表2
    }

    /**
     * 获取计划表2
     * @return array
     */
    public function getPlans2()
    {
        if (is_null($this->plans2)) {
            $mbor = new ModelByOutsideRate(
                $this->leaseAmount, $this->leaseAmountRatio, $this->downPayment, $this->downPaymentRatio, $this->deposit,
                $this->depositRatio, $this->residualValue, $this->residualValueRatio, $this->serviceAmount, $this->serviceAmountRatio,
                $this->interestRate2, $this->issues, $this->otherfees2, $this->paymentMode, $this->issueMonths,
                $this->scale
            );
            $mbor->setFrontPlan($this->getPlans1());
            $this->plans2 = $mbor->getPlan();
            $this->outsideRate2 = $mbor->getOutsideRate();
        }
        return $this->plans2;
    }

    /**
     * 获取计划表2的外部年化利率
     * @return float
     */
    public function getOutsideRate2()
    {
        if (is_null($this->outsideRate2)) {
            $this->getPlans2();
        }
        return $this->outsideRate2;
    }

    /**
     * 获取表2实际内部年化IRR
     * @return float
     */
    public function getInsideRate2()
    {
        if (is_null($this->insideRate2)) {
            $this->getPlans2();
            $cashflow = [];
            foreach ($this->plans2 as $plan) {
                $cashflow[] = $plan['cash_flow'];
            }
            $this->insideRate2 = Financial::irr($cashflow) * 12 / $this->issueMonths;
        }
        return $this->insideRate2;
    }

    /**
     * 设置表3参数
     * @param array $otherfees3 其他费用3
     */
    public function set3($otherfees3 = [])
    {
        $this->otherfees3 = $otherfees3;

        $this->leaseAmount3 = round($this->leaseAmount - $this->leaseAmount2, $this->scale);
        $this->downPayment3 = round($this->downPayment - $this->downPayment2, $this->scale);
        $this->deposit3 = round($this->deposit - $this->deposit2, $this->scale);
        $this->residualValue3 = round($this->residualValue - $this->residualValue2, $this->scale);
        $this->serviceAmount3 = round($this->serviceAmount - $this->serviceAmount2, $this->scale);

        $this->principal3 = round($this->principal - $this->principal2, $this->scale);
        $this->plans3 = null;  // 重新生成计划表3
    }

    /**
     * 获取计划表3
     * @return array
     */
    public function getPlans3()
    {
        if (is_null($this->plans3)) {
            $plans1 = $this->getPlans1();
            $plans2 = $this->getPlans2();
            $plan = [];
            for ($i = 0; $i <= $this->issues; $i++) {
                $issue = $plans2[$i]['issue'];
                $row = [];
                $row['issue'] = $issue;
                if (isset($plans2[$i]['payment_date'])) {
                    $row['payment_date'] = $plans2[$i]['payment_date'];
                }
                $row['rent'] = round($plans1[$i]['rent'] - $plans2[$i]['rent'], $this->scale);
                $row['capital'] = round($plans1[$i]['capital'] - $plans2[$i]['capital'], $this->scale);
                $row['interest'] = round($plans1[$i]['interest'] - $plans2[$i]['interest'], $this->scale);
                $row['balance'] = round($plans1[$i]['balance'] - $plans2[$i]['balance'], $this->scale);
                $row['residual_value'] = round($plans1[$i]['residual_value'] - $plans2[$i]['residual_value'], $this->scale);
                $row['deposit_deduction'] = round($plans1[$i]['deposit_deduction'] - $plans2[$i]['deposit_deduction'], $this->scale);
                $row['cash_flow'] = ($this->paymentMode == 1 && $i == $this->issues) ? 0 : round($row['rent'] - $row['deposit_deduction'] + $row['residual_value'], $this->scale);  // 现金流 = 租金 - 预付抵扣 + 留购
                $row['nominal_cash_flow'] = ($this->paymentMode == 1 && $i == $this->issues) ? 0 : round($row['rent'] + $row['residual_value'], $this->scale);  // 名义现金流 = 租金 + 留购
                $row['otherfee'] = 0;
                $row['payable_amount'] = 0;
                $plan[] = $row;
            }
            $plan[0]['cash_flow'] = -round(round($this->principal3 - $this->deposit3, $this->scale) - $plan[0]['rent'] - $this->serviceAmount3, $this->scale);  // 现金流 = -(转让价款 - 首付租金 - 预付抵扣 - 租前租金)
            $plan[0]['nominal_cash_flow'] = -$plan[0]['balance']; //名义现金流 = -剩余本金
            $plan[0]['payable_amount'] = -$plan[0]['cash_flow']; //应付金额 = 转让价款 - 首付租金 - 保证金 - 租前租金
            // 其他费用
            if (!empty($this->otherfees3)) {
                foreach ($this->otherfees3 as $fee) {
                    $plan[$fee['issue']]['cash_flow'] = round($plan[$fee['issue']]['cash_flow'] + $fee['amount'], $this->scale);
                    $plan[$fee['issue']]['otherfee'] = round($plan[$fee['issue']]['otherfee'] + $fee['amount'], $this->scale);
                }
            }
            // 应付金额
            $plan[0]['payable_amount'] = -$plan[0]['cash_flow'];
            for ($i = 1; $i <= $this->issues; $i++) {
                // 应付金额 = 租金 - 保证金抵扣 + 留购价 + 其他费用
                $plan[$i]['payable_amount'] = $plan[$i]['rent'] - $plan[$i]['deposit_deduction'] + $plan[$i]['residual_value'] + $plan[$i]['otherfee'];
            }
            $this->plans3 = $plan;
        }
        return $this->plans3;
    }

    /**
     * 获取表3实际内部年化IRR
     * @return float
     */
    public function getInsideRate3()
    {
        if (is_null($this->insideRate3)) {
            $this->getPlans3();
            $cashflow = [];
            foreach ($this->plans3 as $plan) {
                $cashflow[] = $plan['cash_flow'];
            }
            $this->insideRate3 = Financial::irr($cashflow) * 12 / $this->issueMonths;
        }
        return $this->insideRate3;
    }

    /**
     * 设置表4参数
     * @param float $leaseAmountRatio4   针对表3的转让价款比例
     * @param float $downPaymentRatio4   针对表3的首付款比例
     * @param float $depositRatio4       针对表3的预付款比例
     * @param float $residualValueRatio4 针对表3的留购价比例
     * @param float $serviceAmountRatio4 针对表3的手续费比例
     * @param float $interestRate4       内部年化IRR4
     * @param array $otherfees4          其他费用4
     */
    public function set4($leaseAmountRatio4, $downPaymentRatio4, $depositRatio4, $residualValueRatio4, $serviceAmountRatio4, $interestRate4, $otherfees4 = [])
    {
        $this->leaseAmountRatio4 = $leaseAmountRatio4;
        $this->downPaymentRatio4 = $downPaymentRatio4;
        $this->depositRatio4 = $depositRatio4;
        $this->residualValueRatio4 = $residualValueRatio4;
        $this->serviceAmountRatio4 = $serviceAmountRatio4;
        $this->interestRate4 = $interestRate4;
        $this->otherfees4 = $otherfees4;

        $this->leaseAmount4 = round($this->leaseAmount3 * $this->leaseAmountRatio4, $this->scale);
        $this->downPayment4 = round($this->downPayment3 * $this->downPaymentRatio4, $this->scale);
        $this->deposit4 = round($this->deposit3 * $this->depositRatio4, $this->scale);
        $this->residualValue4 = round($this->residualValue3 * $this->residualValueRatio4, $this->scale);
        $this->serviceAmount4 = round($this->serviceAmount3 * $this->serviceAmountRatio4, $this->scale);

        $this->principal4 = round($this->leaseAmount4 - $this->downPayment4, $this->scale);
        $this->plans4 = null;  // 重新生成计划表4
    }

    /**
     * 获取计划表4
     * @return array
     */
    public function getPlans4()
    {
        if (is_null($this->plans4)) {
            $mbor = new ModelByOutsideRate(
                $this->leaseAmount3, $this->leaseAmountRatio4, $this->downPayment3, $this->downPaymentRatio4, $this->deposit3,
                $this->depositRatio4, $this->residualValue3, $this->residualValueRatio4, $this->serviceAmount3, $this->serviceAmountRatio4,
                $this->interestRate4, $this->issues, $this->otherfees4, $this->paymentMode, $this->issueMonths,
                $this->scale
            );
            $mbor->setFrontPlan($this->getPlans3());
            $this->plans4 = $mbor->getPlan($this->startDate);
            $this->outsideRate4 = $mbor->getOutsideRate();
        }
        return $this->plans4;
    }

    /**
     * 获取表4的外部年化利率
     * @return float
     */
    public function getOutsideRate4()
    {
        if (is_null($this->outsideRate4)) {
            $this->getPlans4();
        }
        return $this->outsideRate4;
    }

    /**
     * 获取表4实际内部年化IRR
     * @return float
     */
    public function getInsideRate4()
    {
        if (is_null($this->insideRate4)) {
            $this->getPlans4();
            $cashflow = [];
            foreach ($this->plans4 as $plan) {
                $cashflow[] = $plan['cash_flow'];
            }
            $this->insideRate4 = Financial::irr($cashflow) * 12 / $this->issueMonths;
        }
        return $this->insideRate4;
    }

    /**
     * 设置表5参数
     * @param array $otherfees5 其他费用5
     */
    public function set5($otherfees5 = [])
    {
        $this->otherfees5 = $otherfees5;

        $this->leaseAmount5 = round($this->leaseAmount3 - $this->leaseAmount4, $this->scale);
        $this->downPayment5 = round($this->downPayment3 - $this->downPayment4, $this->scale);
        $this->deposit5 = round($this->deposit3 - $this->deposit4, $this->scale);
        $this->residualValue5 = round($this->residualValue3 - $this->residualValue4, $this->scale);
        $this->serviceAmount5 = round($this->serviceAmount3 - $this->serviceAmount4, $this->scale);

        $this->principal5 = round($this->principal3 - $this->principal4, $this->scale);
        $this->plans5 = null;  // 重新生成计划表5
    }

    public function getPlans5()
    {
        if (is_null($this->plans5)) {
            $plans3 = $this->getPlans3();
            $plans4 = $this->getPlans4();
            $plan = [];
            for ($i = 0; $i <= $this->issues; $i++) {
                $issue = $plans4[$i]['issue'];
                $row = [];
                $row['issue'] = $issue;
                if (isset($plans4[$i]['payment_date'])) {
                    $row['payment_date'] = $plans4[$i]['payment_date'];
                }
                $row['rent'] = round($plans3[$i]['rent'] - $plans4[$i]['rent'], $this->scale);
                $row['capital'] = round($plans3[$i]['capital'] - $plans4[$i]['capital'], $this->scale);
                $row['interest'] = round($plans3[$i]['interest'] - $plans4[$i]['interest'], $this->scale);
                $row['balance'] = round($plans3[$i]['balance'] - $plans4[$i]['balance'], $this->scale);
                $row['residual_value'] = round($plans3[$i]['residual_value'] - $plans4[$i]['residual_value'], $this->scale);
                $row['deposit_deduction'] = round($plans3[$i]['deposit_deduction'] - $plans4[$i]['deposit_deduction'], $this->scale);
                $row['cash_flow'] = ($this->paymentMode == 1 && $i == $this->issues) ? 0 : round($row['rent'] - $row['deposit_deduction'] + $row['residual_value'], $this->scale);  // 现金流 = 租金 - 预付抵扣 + 留购
                $row['nominal_cash_flow'] = ($this->paymentMode == 1 && $i == $this->issues) ? 0 : round($row['rent'] + $row['residual_value'], $this->scale);  // 名义现金流 = 租金 + 留购
                $row['otherfee'] = 0;
                $row['payable_amount'] = 0;
                $plan[] = $row;
            }
            $plan[0]['cash_flow'] = -round(round($this->principal5 - $this->deposit5, $this->scale) - $plan[0]['rent'] - $this->serviceAmount5, $this->scale);  // 现金流 = -(转让价款 - 首付租金 - 预付抵扣 - 租前租金)
            $plan[0]['nominal_cash_flow'] = -$plan[0]['balance']; //名义现金流 = -剩余本金
            $plan[0]['payable_amount'] = -$plan[0]['cash_flow']; //应付金额 = 转让价款 - 首付租金 - 保证金 - 租前租金
            // 其他费用
            if (!empty($this->otherfees5)) {
                foreach ($this->otherfees5 as $fee) {
                    $plan[$fee['issue']]['cash_flow'] = round($plan[$fee['issue']]['cash_flow'] + $fee['amount'], $this->scale);
                    $plan[$fee['issue']]['otherfee'] = round($plan[$fee['issue']]['otherfee'] + $fee['amount'], $this->scale);
                }
            }
            // 应付金额
            $plan[0]['payable_amount'] = -$plan[0]['cash_flow'];
            for ($i = 1; $i <= $this->issues; $i++) {
                // 应付金额 = 租金 - 保证金抵扣 + 留购价 + 其他费用
                $plan[$i]['payable_amount'] = $plan[$i]['rent'] - $plan[$i]['deposit_deduction'] + $plan[$i]['residual_value'] + $plan[$i]['otherfee'];
            }
            $this->plans5 = $plan;
        }
        return $this->plans5;
    }
}